/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gene.core;

import gene.core.collection.ComponentCollection;

/**
 *
 * @author callagun
 */
public abstract class Component {
     protected static short id=0;
    /**
     * global components core instance.
     */
    protected static Core          coreInstance = Core.getInstance();
    /**
     * global components graphic device instance
     */
    protected static GraphicDevice graphicsInstance = Core.graphicDevice;
    /**
     * array to save memory size, contains on index
     * 0 type of component , used to control the kind of components
     * 1 component's state.
     * 2 global id component's code
     */
    private short[] type_state_id = {0, 0, 0 };
    /**
     * array to save memory size, contains on index
     * 0 Is initialized
     * 1 Is Visible
     */
    private boolean initialized_visible[] = {false, false};
    /**
     * internal clock tick
     */
    protected int tick;
    /**
     * scene container
     */
    public Scene sceneParent = null;
    /**
     * array to save memory , contains on index
     * 0 component position x
     * 1 component position y
     * 2 component width size
     * 3 component height size
     */
    private short x_y_w_h[] = {0, 0, 0, 0};
    /**
     * array to save memory , contains collision data , on index
     * 0 component collision position x
     * 1 component collision position y
     * 2 component collision width size
     * 3 component collision height size
     */
    private short collisionArea_x_y_w_h[] = {0, 0, 0, 0};
    /**
     * pointer to next component
     */
    public Component next;

    /**
     * Components constructor
     * @param screenParent The scene component owner
     */
    public Component(Scene screenParent) {
	  type_state_id[2]=id;
	   id++;
        initializeComponent(screenParent);
    }


    public int getX() {
        return x_y_w_h[0];
    }

    public int getCollisionAreaX() {
        return collisionArea_x_y_w_h[0];
    }

    public int getY() {
        return x_y_w_h[1];
    }

    public int getCollisionAreaY() {
        return collisionArea_x_y_w_h[1];
    }

    public int getW() {
        return x_y_w_h[2];
    }

    public int getCollisionAreaW() {
        return collisionArea_x_y_w_h[2];
    }

    public int getH() {
        return x_y_w_h[3];
    }

    public int getCollisionAreaH() {
        return collisionArea_x_y_w_h[3];
    }

    public void setX(int x) {
        x_y_w_h[0] = (short) x;
    }

    public void setY(int y) {
        x_y_w_h[1] = (short) y;
    }

    public void setW(int w) {
        x_y_w_h[2] = (short) w;
    }

    public void setH(int h) {
        x_y_w_h[3] = (short) h;
    }

    /**
     * @return <code>initialized_visible</code> index 1;
     */
    public boolean isVisible() {
        return initialized_visible[1];
    }

    public void setVisible(boolean visible) {
        //if(visible){ initialized_visible = initialized_visible | 0x10;}
        initialized_visible[1] = visible;
    }

    public boolean isInitialized() {
        return initialized_visible[0];
    }

    public void getInitialized(boolean initialized) {
        initialized_visible[0] = initialized;
    }

    /**
     * Initialize the component setting him on <code>Screen.components</code>
     * @param screenParent
     */
    protected void initializeComponent(Scene screenParent) {
        if (screenParent.components == null) {
            new Exception("null ComponentCollection exeption");
        }

        if (Core.isInitialized() &&
                screenParent != null) {

            if(screenParent.components == null){
            screenParent.components = new ComponentCollection();
            }

            initialized_visible[0] = true;

            screenParent = screenParent;

            //screenParent.components.add(this);
              screenParent.components.add(this);
        } else {

            screenParent = screenParent;

            screenParent.components.add(this);

        }

    }

    public int getType() {
        return type_state_id[0];
    }

    public int getState() {
        return type_state_id[1];
    }

    public void setState(int state) {
        type_state_id[1] = (short) state;
    }

    /**
     * update the actions , status and anything else in the component
     */
    public abstract void update();

    /**
     * write the component on the screen buffer
     */
    public abstract void draw();

    /**
     * test the colision between current component and any other;
     * @param component
     * @return
     */
    public abstract boolean collidsWith(Component component);

    /**
     * Default bound box collision template
     * @param a First component
     * @param b First component
     * @return true if collids
     */
    protected static boolean collidsWith(Component a, Component b) {

        if (a.getX() + a.getW() < b.getX()) {
            return false;	//just checking if their
        }
        if (a.getX() > b.getX() + b.getW()) {
            return false;	//bounding boxes even touch
        }
        if (a.getY() + a.getH() < b.getY()) {
            return false; //
        }
        if (a.getY() > b.getY() + b.getH()) {
            return false; //
        }
        return true; // collidiu

    }

    
    /**
     * Default setted bound box collision area template
     * @param a First component
     * @param b Second component
     * @return true if collids
     */
    protected static boolean collidsWithCollisionArea(Component a, Component b) {

        if ((a.getX() + a.getCollisionAreaX()) + a.getCollisionAreaW() < b.getX() + b.getCollisionAreaX()) {
            return false;	//just checking if their
        }
        if (a.getX() + a.getCollisionAreaX() >
                b.getX() + b.getCollisionAreaX() + b.getCollisionAreaW()) {
            return false;	//bounding boxes even touch
        }
        if (a.getY() + a.getCollisionAreaY() + a.getCollisionAreaH() <
                b.getY() + b.getCollisionAreaY()) {
            return false; //
        }
        if (a.getY() + a.getCollisionAreaY() >
                b.getY() + b.getCollisionAreaY() + b.getCollisionAreaH()) {
            return false; //
        }
        return true; // collidiu

    }

    /**
     * Move the object 
     * @param x Increment on x axis
     * @param y Increment on y axis
     */
    public abstract void move(int x, int y);

    public abstract void start();

    public abstract void destroy();

    public void updateTick(){
    ++tick;
    }

    public void resetTick(){
    tick = 0;
    }

    public static Component head,  ground;

}
